﻿#pragma once

#include <learn/ais/ais_renderer.h>
#include <learn/dll_ext.h>
#include <learn/geom/vec.h>

#include <functional>

namespace xi
{

namespace ais
{

using namespace xi::geom;

// 前向声明
class EXT_SYMBOL AIS_Object;

struct AIS_Msg
{
    /**
     * @brief 访问接口
     *
     * @param[in] visitor
     */
    virtual void accept(AIS_Object *visitor) = 0;

    /**
     * @brief 虚析构函数
     *
     */
    virtual ~AIS_Msg() = default;
};

template <class Derived> struct AIS_MsgImpl : AIS_Msg
{
    /**
     * @brief CRTP 模式
     *
     * @param[in] visitor
     */
    void accept(AIS_Object *visitor) override;
};

struct AIS_InitMsg : AIS_MsgImpl<AIS_InitMsg>
{
    // 用于创建渲染器的工厂类
    std::shared_ptr<RendererFactory> factory;
};

struct AIS_UpdateMsg : AIS_MsgImpl<AIS_UpdateMsg>
{
};

struct AIS_PaintMsg : AIS_MsgImpl<AIS_PaintMsg>
{
};

struct AIS_ShowMsg : AIS_MsgImpl<AIS_ShowMsg>
{
    bool show{false};
};

struct AIS_MoveMsg : AIS_MsgImpl<AIS_MoveMsg>
{
    Vec3f pos; // 鼠标点击位置对应的空间坐标
    Vec3f dir; // 鼠标点击位置对应的视角方向
};

struct AIS_MouseMsg : AIS_MsgImpl<AIS_MouseMsg>
{
    enum Button
    {
        Left,
        Middle,
        Right
    };

    enum Status
    {
        Move,
        Press,
        Release
    };

    float depth;                          // 记录深度
    Button button;                        // 左中右
    Status status;                        // 悬停/点击/释放
    Vec2f press;                          // 点击位置
    Vec2f move;                           // 移动位置
    AIS_Object *obj{nullptr};             // 目标对象
    std::function<Vec3f(Vec3f)> toScreen; // 坐标转换函数
    std::function<Vec3f(Vec2f)> toSpace;  // 坐标转换函数
    std::function<Vec3f(Vec2f)> emit;     // 射线发射函数
};

struct AIS_DestroyMsg : AIS_MsgImpl<AIS_DestroyMsg>
{
};

} // namespace ais

} // namespace xi
